// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// Package diff实现一个比较两个输入的diff函数
// 使用“diff”工具。
package diff

import (
	"bytes"
	exec "internal/execabs"
	"io/ioutil"
	"os"
	"runtime"
)

// 以diff工具格式返回两个字节数组的diff。
func Diff(prefix string, b1, b2 []byte) ([]byte, error) {
	f1, err := writeTempFile(prefix, b1)
	if err != nil {
		return nil, err
	}
	defer os.Remove(f1)

	f2, err := writeTempFile(prefix, b2)
	if err != nil {
		return nil, err
	}
	defer os.Remove(f2)

	cmd := "diff"
	if runtime.GOOS == "plan9" {
		cmd = "/bin/ape/diff"
	}

	data, err := exec.Command(cmd, "-u", f1, f2).CombinedOutput()
	if len(data) > 0 {
		// 当文件不匹配时，diff以非零状态退出。
		// 只要我们得到输出，就忽略这个失败。
		err = nil
	}

	// 如果我们在Windows上，而差异是Cygwin diff，
	// 机器可以进入这样一种状态，每一个Cygwin
	// 命令工作正常，但会打印一条无用的消息，如：
	// None
	// Cygwin警告：
	// 无法计算快速的CWD指针。如果您正在使用
	// 较新Windows上的较旧Cygwin版本。请更新至最新版本
	// 可从https获得Cygwin版本：
	// 请参阅https:
	// None
	// 跳过该消息，只返回实际差异。
	if len(data) > 0 && !bytes.HasPrefix(data, []byte("--- ")) {
		i := bytes.Index(data, []byte("\n--- "))
		if i >= 0 && i < 80*10 && bytes.Contains(data[:i], []byte(":// cygwin.com/”）{
			data = data[i+1:]
		}
	}

	return data, err
}

func writeTempFile(prefix string, data []byte) (string, error) {
	file, err := ioutil.TempFile("", prefix)
	if err != nil {
		return "", err
	}
	_, err = file.Write(data)
	if err1 := file.Close(); err == nil {
		err = err1
	}
	if err != nil {
		os.Remove(file.Name())
		return "", err
	}
	return file.Name(), nil
}
